//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_member_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_project"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_member_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectMemberApiImpl) CreateRole(ctx context.Context, req *project_member_api.CreateRoleRequest) (*project_member_api.CreateRoleResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.CreateRoleResponse{
			Code:   project_member_api.CreateRoleResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.CreateRoleResponse{
			Code:   project_member_api.CreateRoleResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.CreateRoleResponse{
			Code:   project_member_api.CreateRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_member_api.CreateRoleResponse{
			Code:   project_member_api.CreateRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(roleItem.BasicInfo.Admin) {
		return &project_member_api.CreateRoleResponse{
			Code:   project_member_api.CreateRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	roleId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err := project_dao.MemberRoleDao.Insert(sessCtx, &project_dao.RoleInfoDbItem{
			RoleId:    roleId,
			ProjectId: req.ProjectId,
			BasicInfo: project_dao.BasicRoleInfoDbItem{
				RoleName: req.BasicInfo.RoleName,
				Admin:    req.BasicInfo.Admin,
			},
			CreateTime:  nowTime,
			UpdateTime:  nowTime,
			DefaultRole: false,
		})
		if err != nil {
			return nil, err
		}

		return &project_member_api.CreateRoleResponse{
			Code:   project_member_api.CreateRoleResponse_CODE_OK,
			RoleId: roleId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//add event
	go apiImpl.addCreateRoleEvent(sessionItem, req, projectItem, roleId, nowTime)
	return ret.(*project_member_api.CreateRoleResponse), nil
}

func (apiImpl *ProjectMemberApiImpl) UpdateRole(ctx context.Context, req *project_member_api.UpdateRoleRequest) (*project_member_api.UpdateRoleResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.UpdateRoleResponse{
			Code:   project_member_api.UpdateRoleResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测权限
	projectItem, _, userRoleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.UpdateRoleResponse{
			Code:   project_member_api.UpdateRoleResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.UpdateRoleResponse{
			Code:   project_member_api.UpdateRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	if !(sessionItem.UserId == projectItem.OwnerUserId || userRoleItem.BasicInfo.Admin) {
		return &project_member_api.UpdateRoleResponse{
			Code:   project_member_api.UpdateRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	roleItem, err := project_dao.MemberRoleDao.Get(ctx, req.ProjectId, req.RoleId)
	if err != nil {
		return &project_member_api.UpdateRoleResponse{
			Code:   project_member_api.UpdateRoleResponse_CODE_NO_ROLE,
			ErrMsg: "角色不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err := project_dao.MemberRoleDao.UpdateBasicInfo(sessCtx, req.ProjectId, req.RoleId, &project_dao.BasicRoleInfoDbItem{
			RoleName: req.BasicInfo.RoleName,
			Admin:    req.BasicInfo.Admin,
		})
		if err != nil {
			return nil, err
		}

		return &project_member_api.UpdateRoleResponse{
			Code: project_member_api.UpdateRoleResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//add event
	go apiImpl.addUpdateRoleEvent(sessionItem, req, projectItem, roleItem)
	return ret.(*project_member_api.UpdateRoleResponse), nil
}

func (apiImpl *ProjectMemberApiImpl) RemoveRole(ctx context.Context, req *project_member_api.RemoveRoleRequest) (*project_member_api.RemoveRoleResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.RemoveRoleResponse{
			Code:   project_member_api.RemoveRoleResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测权限
	projectItem, _, userRoleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.RemoveRoleResponse{
			Code:   project_member_api.RemoveRoleResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.RemoveRoleResponse{
			Code:   project_member_api.RemoveRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	//check project close status
	if projectItem.Closed {
		return &project_member_api.RemoveRoleResponse{
			Code:   project_member_api.RemoveRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if projectItem.DefaultRoleId == req.RoleId {
		return &project_member_api.RemoveRoleResponse{
			Code:   project_member_api.RemoveRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(sessionItem.UserId == projectItem.OwnerUserId || userRoleItem.BasicInfo.Admin) {
		return &project_member_api.RemoveRoleResponse{
			Code:   project_member_api.RemoveRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	roleItem, err := project_dao.MemberRoleDao.Get(ctx, req.ProjectId, req.RoleId)
	if err != nil { //记录不存在
		return &project_member_api.RemoveRoleResponse{
			Code: project_member_api.RemoveRoleResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		//检查是否有被引用
		count, err := project_dao.MemberInfoDao.CountByRole(sessCtx, req.ProjectId, req.RoleId)
		if err != nil {
			return nil, err
		}
		if count > 0 {
			return &project_member_api.RemoveRoleResponse{
				Code:   project_member_api.RemoveRoleResponse_CODE_NO_PERMISSION, //XXX
				ErrMsg: "没有权限",
			}, nil
		}
		//更新
		err = project_dao.MemberRoleDao.Remove(sessCtx, req.ProjectId, req.RoleId)
		if err != nil {
			return nil, err
		}

		return &project_member_api.RemoveRoleResponse{
			Code: project_member_api.RemoveRoleResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//add event
	go apiImpl.addRemoveRoleEvent(sessionItem, req, projectItem, roleItem)
	return ret.(*project_member_api.RemoveRoleResponse), nil
}

func (apiImpl *ProjectMemberApiImpl) ListRole(ctx context.Context, req *project_member_api.ListRoleRequest) (*project_member_api.ListRoleResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.ListRoleResponse{
			Code:   project_member_api.ListRoleResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.ListRoleResponse{
			Code:   project_member_api.ListRoleResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.ListRoleResponse{
			Code:   project_member_api.ListRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	roleItemList, err := project_dao.MemberRoleDao.ListByProjectId(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}
	roleList := []*project_member_api.RoleInfo{}
	for _, roleItem := range roleItemList {
		roleList = append(roleList, roleItem.ToRoleInfo())
	}
	return &project_member_api.ListRoleResponse{
		Code:     project_member_api.ListRoleResponse_CODE_OK,
		RoleList: roleList,
	}, nil
}

func (apiImpl *ProjectMemberApiImpl) SetMemberRole(ctx context.Context, req *project_member_api.SetMemberRoleRequest) (*project_member_api.SetMemberRoleResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_member_api.SetMemberRoleResponse{
			Code:   project_member_api.SetMemberRoleResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检测权限
	projectItem, _, userRoleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_member_api.SetMemberRoleResponse{
			Code:   project_member_api.SetMemberRoleResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_member_api.SetMemberRoleResponse{
			Code:   project_member_api.SetMemberRoleResponse_CODE_NO_ROLE,
			ErrMsg: "角色不存在",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_member_api.SetMemberRoleResponse{
			Code:   project_member_api.SetMemberRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if !(sessionItem.UserId == projectItem.OwnerUserId || userRoleItem.BasicInfo.Admin) {
		return &project_member_api.SetMemberRoleResponse{
			Code:   project_member_api.SetMemberRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if req.MemberUserId == projectItem.OwnerUserId {
		return &project_member_api.SetMemberRoleResponse{
			Code:   project_member_api.SetMemberRoleResponse_CODE_NO_PERMISSION,
			ErrMsg: "不能修改项目所有者的角色",
		}, nil
	}
	roleItem, err := project_dao.MemberRoleDao.Get(ctx, req.ProjectId, req.RoleId)
	if err != nil {
		return &project_member_api.SetMemberRoleResponse{
			Code:   project_member_api.SetMemberRoleResponse_CODE_NO_ROLE,
			ErrMsg: "角色不存在",
		}, nil
	}
	exist, err := project_dao.MemberInfoDao.Exist(ctx, req.ProjectId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_member_api.SetMemberRoleResponse{
			Code:   project_member_api.SetMemberRoleResponse_CODE_NO_MEMBER,
			ErrMsg: "成员不存在",
		}, nil
	}
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_dao.MemberInfoDao.UpdateRole(sessCtx, req.ProjectId, req.MemberUserId, req.RoleId)
		if err != nil {
			return nil, err
		}
		return &project_member_api.SetMemberRoleResponse{
			Code: project_member_api.SetMemberRoleResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	userItem, err := user_dao.UserInfoDao.Get(ctx, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	go apiImpl.addSetMemberRoleEvent(sessionItem, req, projectItem, roleItem, userItem)
	go api_common.SendNoticeToUser(context.Background(), req.MemberUserId, &notices_project.SetMemberRoleNotice{
		ProjectId:    req.ProjectId,
		MemberUserId: req.MemberUserId,
		RoleId:       req.RoleId,
	})
	return ret.(*project_member_api.SetMemberRoleResponse), nil
}
